﻿// --------------------------------------------------------------------------------------------------------------------
// <copyright file="FilesEnumerator.cs" company="" />
// <summary>
//   Collect list of files and directories, and create a collection of files.
// </summary>
// --------------------------------------------------------------------------------------------------------------------

namespace Utilities
{
    using System;
    using System.Collections.Generic;
    using System.Globalization;
    using System.IO;

    /// <summary>
    /// Collect list of files and directories, and create a collection of files.
    /// Any relevant path is either absolute, or relative to the current-working directory.
    /// </summary>
    public class FilesEnumerator
    {
        /// <summary>
        /// The enumeration attributes set for a given file/directory path. Paths are kept in absolute path format.
        /// </summary>
        private readonly Dictionary<string, PathEntryAttributes> m_pathEntries = new Dictionary<string, PathEntryAttributes>();

        /// <summary>
        /// The list of required files with absolute paths.
        /// </summary>
        private readonly List<string> m_paths = new List<string>();

        /// <summary>
        /// Add attributes to a given path.
        /// When setting attributes to an already existing path entry, the effect is only to add the given file-patterns to the ones already set.
        /// </summary>
        /// <param name="path">The path to set attributes for.</param>
        /// <param name="pathAttributes">The attributes to give to the path.</param>
        public void Add(string path, PathEntryAttributes pathAttributes)
        {
            if (pathAttributes == null)
            {
                throw new ArgumentNullException("pathAttributes");
            }

            string absolutePath = Path.GetFullPath(path);
            if (m_pathEntries.ContainsKey(absolutePath))
            {
                m_pathEntries[absolutePath].FilePattern += PathEntryAttributes.FilePatternsSeparator + pathAttributes.FilePattern;
            }
            else
            {
                m_pathEntries.Add(absolutePath, pathAttributes);
            }
        }

        /// <summary>
        /// Remove the enumeration attributes for a given path.
        /// </summary>
        /// <param name="path">The path to remove attributes for.</param>
        public void Remove(string path)
        {
            string absolutePath = Path.GetFullPath(path);

            if (!m_pathEntries.ContainsKey(absolutePath))
            {
                throw new InvalidOperationException(string.Format(CultureInfo.InvariantCulture, "There's no path entry for '{0}' to remove.", path));
            }

            m_pathEntries.Remove(absolutePath);
        }

        /// <summary>
        /// Enumerate the files according to definitions into a list.
        /// </summary>
        public void PrepareFileList()
        {
            m_paths.Clear();

            foreach (var pathEntry in m_pathEntries)
            {
            }
        }

        /// <summary>
        /// Gets the enumeration of the files as deducted from the given enumeration definitions.
        /// This enumeration is already calculated and ready.
        /// </summary>
        public IEnumerable<string> Paths
        {
            get
            {
                return m_paths;
            }
        }

        /// <summary>
        /// Matches the given path to a given attributes entry, and populates the list of paths with appropriated matching file absolute paths.
        /// </summary>
        /// <param name="path">The given path to populate by its attributes.</param>
        /// <param name="attributes">The path entry attributes.</param>
        private void CreatePathsList(string path, PathEntryAttributes attributes)
        {
            if (attributes.IsDirectory)
            {
                // 'path' is a directory:
            }
            else
            {
                // 'path' is a file:
                m_paths.Add(path);
            }
        }
    }

    /// <summary>
    /// Defines attributes for enumerating a path entry.
    /// </summary>
    public class PathEntryAttributes
    {
        /// <summary>
        /// A separator used to separate given file patterns for file enumeration.
        /// </summary>
        public const char FilePatternsSeparator = ';';

        /// <summary>
        /// Initializes a new instance of the <see cref="PathEntryAttributes"/> class, setting the attributes of the entry.
        /// </summary>
        /// <param name="isDirectory">Whether this is a directory.</param>
        /// <param name="filePattern">If this is a directory - The file pattern to enumerate. Can have more than one pattern, separated by ';'.</param>
        /// <param name="isRecursive">If this is a directory - whether enumeration should recursive for files.</param>
        public PathEntryAttributes(bool isDirectory = false, string filePattern = "*.*", bool isRecursive = false)
        {
            IsDirectory = isDirectory;
            FilePattern = filePattern;
            IsRecursive = isRecursive;
        }

        /// <summary>
        /// Gets a value indicating whether this entry path refers to a directory.
        /// </summary>
        public bool IsDirectory { get; private set; }

        /// <summary>
        /// Gets the file pattern to enumerate, case this entry refers to a directory.
        /// </summary>
        public string FilePattern { get; internal set; }

        /// <summary>
        /// Gets a value indicating whether this directory entry path should also be recursive in enumeration. Irrelevant for file-entry-paths.
        /// </summary>
        public bool IsRecursive { get; private set; }
    }
}
